#include "AutoGenSupportIncludeOnce.hpp"

#ifdef __DEBUG_RSTREAM_GENERATED__
#include "AutoGenSupport.debug.hpp"
#else
// Needs to be included multiple times with the proper #define set at each inclusion

#ifdef __EDT_DECL__
#define RSTREAM_EDT_DECL(ID, TOTDIM, ITDIM)                            \
  EDT_DECL(STARTUP_CODELET_NAME(ID, TOTDIM, ITDIM));                   \
  EDT_DECL(WORKER_CODELET_NAME(ID, TOTDIM, ITDIM));                    \
  EDT_DECL(SHUTDOWN_CODELET_NAME(ID, TOTDIM, ITDIM));
#endif // __EDT_DECL__

#ifdef __COUNTING_DEP_DECL__
#define RSTREAM_COUNTING_DEP_DECL(ID, TOTDIM, ITDIM)    \
  swarm_Dep_t COUNTING_DEP_NAME(ID, TOTDIM, ITDIM);
#endif // __COUNTING_DEP_DECL__

#ifdef __COUNTING_DEP_EXTERN_DECL__
#define RSTREAM_COUNTING_DEP_EXTERN_DECL(ID, TOTDIM, ITDIM)     \
  extern swarm_Dep_t COUNTING_DEP_NAME(ID, TOTDIM, ITDIM);
#endif // __COUNTING_DEP_EXTERN_DECL__

#ifdef __COUNTING_DEP_INIT__
#define RSTREAM_COUNTING_DEP_INIT(ID, TOTDIM, ITDIM, COUNTERNAME)      \
  swarm_Dep_init(&(COUNTING_DEP_NAME(ID, TOTDIM, ITDIM)), COUNTERNAME, \
                 &CODELET(SHUTDOWN_CODELET_NAME(ID,TOTDIM,ITDIM)), \
                 NULL, NULL);
#endif // __COUNTING_DEP_INIT__

#ifdef __COUNTING_DEP_SATISFY_ONCE__
#define RSTREAM_COUNTING_DEP_SATISFY_ONCE(ID, TOTDIM, ITDIM)            \
  swarm_Dep_satisfyOnce(&(COUNTING_DEP_NAME(ID, TOTDIM, ITDIM)));
#endif // __COUNTING_DEP_SATISFY_ONCE__




#ifdef __TAG_TABLE_DECL__
#define RSTREAM_TAG_TABLE_DECL(ID, TOTDIM, ITDIM)    \
  swarm_TagTable_t TAG_TABLE_NAME(ID, TOTDIM, ITDIM);
#endif // __TAG_TABLE_DECL__

#ifdef __TAG_TABLE_EXTERN_DECL__
#define RSTREAM_TAG_TABLE_EXTERN_DECL(ID, TOTDIM, ITDIM)    \
  extern swarm_TagTable_t TAG_TABLE_NAME(ID, TOTDIM, ITDIM);
#endif // __TAG_TABLE_EXTERN_DECL__

#ifdef __TAG_TABLE_INIT__
#define RSTREAM_TAG_TABLE_INIT(ID, TOTDIM, ITDIM, SIZE)      \
  swarm_TagTable_init(&TAG_TABLE_NAME(ID, TOTDIM, ITDIM), SIZE);  
#endif // __TAG_TABLE_INIT__




#ifdef __TASK_TAG_INIT__
#define RSTREAM_TASK_TAG_INIT(TAGWNAME, ID, TOTDIM, ITDIM, ...)           \
    SwarmTaskTag<ID, TOTDIM, ITDIM> *t = new SwarmTaskTag<ID, TOTDIM, ITDIM> (__VA_ARGS__); \
    SwarmTagWrapper<SwarmTaskTag<ID, TOTDIM, ITDIM> > *TAGWNAME =            \
      new SwarmTagWrapper<SwarmTaskTag<ID, TOTDIM, ITDIM> > (t);
#endif // __TASK_TAG_INIT__

#ifdef __TASK_SCHEDULE__
#define RSTREAM_TASK_SCHEDULE(TAGWNAME, ID, TOTDIM, ITDIM, ...)           \
  swarm_schedule(&swarm_CodeletDesc_CODELET(WORKER_CODELET_NAME(ID, TOTDIM, ITDIM)), TAGWNAME, NULL, NULL, NULL); 
#endif // __TASK_SCHEDULE__

#ifdef __TASK_TAG_INIT_AND_SCHEDULE_STARTUP__
#define RSTREAM_TASK_TAG_INIT_AND_SCHEDULE_STARTUP(ID, TOTDIM, ITDIM, ...)           \
  SwarmTaskTag<ID, TOTDIM, ITDIM> *t = new SwarmTaskTag<ID, TOTDIM, ITDIM> (__VA_ARGS__); \
  SwarmTagWrapper<SwarmTaskTag<ID, TOTDIM, ITDIM> > *TAGWNAME =         \
    new SwarmTagWrapper<SwarmTaskTag<ID, TOTDIM, ITDIM> > (t);          \
  swarm_schedule(&swarm_CodeletDesc_CODELET(STARTUP_CODELET_NAME(ID, TOTDIM, ITDIM)), TAGWNAME, NULL, NULL, NULL);
#endif // __TASK_TAG_INIT_AND_SCHEDULE_STARTUP__

#ifdef __TASK_TAG_INIT_AND_SCHEDULE_WORKER__
#define RSTREAM_TASK_TAG_INIT_AND_SCHEDULE_WORKER(ID, TOTDIM, ITDIM, ...)           \
  SwarmTaskTag<ID, TOTDIM, ITDIM> *t = new SwarmTaskTag<ID, TOTDIM, ITDIM> (__VA_ARGS__); \
  SwarmTagWrapper<SwarmTaskTag<ID, TOTDIM, ITDIM> > *TAGWNAME =         \
    new SwarmTagWrapper<SwarmTaskTag<ID, TOTDIM, ITDIM> > (t);          \
  swarm_schedule(&swarm_CodeletDesc_CODELET(WORKER_CODELET_NAME(ID, TOTDIM, ITDIM)), TAGWNAME, NULL, NULL, NULL);
#endif // __TASK_TAG_INIT_AND_SCHEDULE_WORKER__

#ifdef __START_RUNTIME__
#define RSTREAM_START_RUNTIME(TAGWNAME, ID, TOTDIM, ITDIM)           \
swarm_posix_enterRuntime(NULL, &CODELET(STARTUP_CODELET_NAME(ID, TOTDIM, ITDIM)), TAGWNAME, NULL);
#endif // __START_RUNTIME__

#ifdef __STOP_RUNTIME__
#define RSTREAM_STOP_RUNTIME(ID, TOTDIM, ITDIM)           \
swarm_shutdownRuntime(NULL);
#endif // __STOP_RUNTIME__

#ifdef __TASK_TAG_INIT_AND_START_RUNTIME__
#define RSTREAM_TASK_TAG_INIT_AND_START_RUNTIME(ID, TOTDIM, ITDIM, ...)           \
  SwarmTaskTag<ID, TOTDIM, ITDIM> *t = new SwarmTaskTag<ID, TOTDIM, ITDIM> (__VA_ARGS__); \
  SwarmTagWrapper<SwarmTaskTag<ID, TOTDIM, ITDIM> > *TAGWNAME =         \
    new SwarmTagWrapper<SwarmTaskTag<ID, TOTDIM, ITDIM> > (t);          \
  swarm_posix_enterRuntime(NULL, &CODELET(STARTUP_CODELET_NAME(ID, TOTDIM, ITDIM)), TAGWNAME, NULL);
#endif // __TASK_TAG_INIT_AND_START_RUNTIME__

#ifdef __TASK_TAG_GET__
#define RSTREAM_TASK_TAG_GET(SWARMWRAPPERPTR, TAGVAR, ID, TOTDIM, ITDIM)   \
  typedef const SwarmTaskTag<ID, TOTDIM, ITDIM> &local_tag_t;            \
  const SwarmTagWrapper<SwarmTaskTag<ID, TOTDIM, ITDIM>> *SWARMWRAPPERPTR = \
    SwarmTagWrapper<SwarmTaskTag<ID, TOTDIM, ITDIM> >::                 \
    _cast_fromAny((swarm_Any_i *)(void *)THIS);                         \
  local_tag_t TAGVAR = *SWARMWRAPPERPTR->tInst;
  // const SwarmTaskTag<ID, TOTDIM, ITDIM> *TAGVAR = tag_wrapper->tInst;
#endif // __TASK_TAG_GET__

#ifdef __TASK_GET__
#define RSTREAM_TASK_GET(TAGVAR, ID, TOTDIM, ITDIM)                     \
  bool suspend = asyncGets(THIS,                                        \
                           swarm_CodeletDesc_CODELET(WORKER_CODELET_NAME(ID, TOTDIM, ITDIM)), \
                           TAG_TABLE_NAME(ID, TOTDIM, ITDIM),                     \
                           TAGVAR);                                     \
  if (suspend) return;
#endif // __TASK_GET__

#ifdef __TASK_PUT__
#define RSTREAM_TASK_PUT(SWARMWRAPPERPTR, TAGVAR, ID, TOTDIM, ITDIM) \
  swarm_TagTable_put(&TAG_TABLE_NAME(ID, TOTDIM, ITDIM),                \
                     SWARMWRAPPERPTR->_cast_toIdentifiable(),           \
                     NULL, swarm_TagTable_COUNT_IMMORTAL, NULL, NULL);
#endif // __TASK_PUT__



#ifdef __EDT_DECL__
#define EDT_DECL(NAME)                  \
  extern swarm_CodeletDesc_DECL(NAME);
#endif // __EDT_DECL__

#ifdef __EDT_DEF__
#define RSTREAM_BEGIN_STARTUP_EDT_DEF(ID, TOTDIM, ITDIM)                        \
  swarm_CodeletDesc_IMPL_NOCANCEL_NOCAST(STARTUP_CODELET_NAME(ID, TOTDIM, ITDIM), STARTUP_CODELET_NAME(ID, TOTDIM, ITDIM), swarm_c_void, swarm_c_void)

#define RSTREAM_END_STARTUP_EDT_DEF(ID, TOTDIM, ITDIM)  \
  swarm_CodeletDesc_IMPL_END;

#define RSTREAM_BEGIN_SHUTDOWN_EDT_DEF(ID, TOTDIM, ITDIM)                        \
  swarm_CodeletDesc_IMPL_NOCANCEL_NOCAST(SHUTDOWN_CODELET_NAME(ID, TOTDIM, ITDIM), SHUTDOWN_CODELET_NAME(ID, TOTDIM, ITDIM), swarm_c_void, swarm_c_void)

#define RSTREAM_END_SHUTDOWN_EDT_DEF(ID, TOTDIM, ITDIM)  \
  swarm_CodeletDesc_IMPL_END;

#define RSTREAM_BEGIN_WORKER_EDT_DEF(ID, TOTDIM, ITDIM)                        \
  swarm_CodeletDesc_IMPL_NOCANCEL(WORKER_CODELET_NAME(ID, TOTDIM, ITDIM), WORKER_CODELET_NAME(ID, TOTDIM, ITDIM), swarm_c_void, swarm_c_void)

#define RSTREAM_END_WORKER_EDT_DEF(ID, TOTDIM, ITDIM)  \
  swarm_CodeletDesc_IMPL_END;
#endif // __EDT_DEF__




#ifdef __TASK_DEF__
// First instantiation and then def
#define RSTREAM_TASK_DEF(ID, TOTDIM, ITDIM)                 \
  template <> void SWARMTask <ID, (TOTDIM-ITDIM), TOTDIM, ITDIM>::operator()() {  
#endif // __TASK_DEF__


#ifdef __DEP_DIST_DEF__
#define RSTREAM_DEP_DIST_DEF(args...)                                       \
  static constexpr auto dists = std::make_tuple(ConstantTerm(), ##args);
#endif // __DEP_DIST_DEF__

#ifdef __DEP_DIST_DEF__
#define RSTREAM_DEP_DIST_NO_DEF()                                       \
  static constexpr auto dists = std::make_tuple(ConstantTerm());
#endif // __DEP_DIST_DEF__



///////////////////// TBD /////////////////////////////////////
#ifdef __EDT_INITIALIZATION__
#define RSTREAM_EDT_INITIALIZATION(ID, TOTDIM, ITDIM)   \
  m_tags_##ID.prescribes( m_steps_##ID, *this );        \
  m_steps_##ID.consumes( items_##ID );                  \
  m_steps_##ID.produces( items_##ID );
#endif //__EDT_INITIALIZATION__


#endif // __DEBUG_RSTREAM_GENERATED__



